module wad.dfh;

import core.sys.windows.windows;

private extern (Windows) LRESULT wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) nothrow {
	switch (msg) {
	case WM_DROPFILES:
		auto hDrop = cast(HDROP)wParam;
		DropHandler handler = void;
		handler.ptr = cast(void*)GetWindowLongPtr(hWnd, 0);
		handler.funcptr = cast(void function(HDROP)nothrow)GetWindowLongPtr(hWnd, LONG_PTR.sizeof);
		handler(hDrop);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_NCACTIVATE:
		return 1;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	case WM_NCCALCSIZE:
	}
	return 0;
}

alias DropHandler = void delegate(HDROP hDrop) nothrow;

struct DropFilesHelper {
	// 定义窗口类
	static immutable CLASS_NAME = "DropFilesHelper"w;

	private HWND hWnd;

	this(DropHandler handler) {
		WNDCLASSEX wc;
		wc.cbSize = wc.sizeof;
		wc.lpfnWndProc = &wndProc;
		wc.lpszClassName = CLASS_NAME.ptr;
		wc.style = CS_HREDRAW | CS_VREDRAW;
		wc.hCursor = LoadCursor(null, IDC_ARROW);
		wc.hbrBackground = cast(HBRUSH)(COLOR_BACKGROUND + 1);
		wc.cbWndExtra = handler.sizeof;
		//wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
		wc.hIconSm = LoadIcon(null, IDI_APPLICATION);
		HINSTANCE hInstance = GetModuleHandle(null);
		wc.hInstance = hInstance;
		//wc.cbClsExtra = 0;
		RegisterClassEx(&wc);

		hWnd = CreateWindowEx(
			WS_EX_LAYERED,
			CLASS_NAME.ptr,
			CLASS_NAME.ptr,
			WS_OVERLAPPED,
			CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
			null,
			null,
			hInstance,
			null
		);
		if (hWnd) {
			SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~(
					WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME) | WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_ACCEPTFILES);
			SetWindowLongPtr(hWnd, 0, cast(LONG_PTR)handler.ptr);
			SetWindowLongPtr(hWnd, LONG_PTR.sizeof, cast(LONG_PTR)handler.funcptr);
			// 使窗口透明
			SetLayeredWindowAttributes(hWnd, 0, 100, LWA_ALPHA);
		}
	}

	bool opCast(T : bool)() const => hWnd !is null;

	bool show() => ShowWindow(hWnd, SW_SHOW) != 0;

	bool hide() => ShowWindow(hWnd, SW_HIDE) != 0;

	/// Get or set the window position.
	@property RECT position() {
		RECT rect = void;
		GetWindowRect(hWnd, &rect);
		return rect;
	}

	/// ditto
	@property void position(RECT rect) {
		SetWindowPos(hWnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
			SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_DRAWFRAME);
	}

	bool setPosition(int x, int y, int w, int h)
		=> SetWindowPos(hWnd, HWND_TOPMOST, x, y, w, h,
			SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_DRAWFRAME) != 0;
}

version (none) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
	HWND hWnd;
	hWnd = DropFilesHelper((HDROP hDrop) {
		const count = DragQueryFile(hDrop, 0xFFFFFFFF, null, 0);
		foreach (i; 0 .. count) {
			const size = DragQueryFile(hDrop, i, null, 0);
			auto szFile = new wchar[size + 1];
			DragQueryFile(hDrop, i, szFile.ptr, size + 1);
			MessageBox(hWnd, szFile.ptr, "", 0);
		}
	}).hWnd;
	// 创建失败
	if (!hWnd)
		return -1;

	MSG msg = void;
	while (GetMessage(&msg, null, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}
